#include "stdafx.h"
#include "CppUnitTest.h"

#include <vex/core/config.h>
#include <vex/core/contract/handle.h>
#include <vex/core/contract/memory_resource.h>
#include <iostream>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace tests { namespace core_config {

    TEST_CLASS(test_class)
    {
        BEGIN_TEST_CLASS_ATTRIBUTE()
            TEST_CLASS_ATTRIBUTE(L"Module", L"tests.core.config")
        END_TEST_CLASS_ATTRIBUTE();
    public:
        TEST_METHOD(wlog_message_behaves_as_expected_for_lvalue_message)
        {
            VEX_TESTS_SCOPED_MEM_CHECK();
            wlog_message msg;

            {
                std::wstring t_str = msg
                    << L"aha" << L"," << L"uha" | as_string;

                Assert::AreEqual(std::wstring(L"aha,uha"), t_str);
            }

            {
                std::wstring t_str = msg
                    << L"aha2" << L"," << L"uha2" | as_string;

                Assert::AreEqual(std::wstring(L"aha2,uha2"), t_str);
            }
        }

        TEST_METHOD(wlog_message_behaves_as_expected_for_rvalue_message)
        {
            VEX_TESTS_SCOPED_MEM_CHECK();
            
            {
                std::wstring t_str = wlog_message()
                    << L"aha" << L"," << L"uha" | as_string;

                Assert::AreEqual(std::wstring(L"aha,uha"), t_str);
            }

            {
                std::wstring t_str = wlog_message()
                    << L"aha2" << L"," << L"uha2" | as_string;

                Assert::AreEqual(std::wstring(L"aha2,uha2"), t_str);
            }
        }

#ifdef VEX_HAS_CPP_11_FEATURE_SET_1
        TEST_METHOD(vex_has_cpp_11_feature_set_1)
        {
            Logger::WriteMessage(wlog_message()
                << "_MSC_VER = " << _MSC_VER << std::endl | as_string);
            Assert::IsTrue(1600 <= boost::lexical_cast<int>(_MSC_VER));
        }
#endif

#ifdef VEX_HAS_CPP_11_FEATURE_SET_2
        TEST_METHOD(vex_has_cpp_11_feature_set_2)
        {
            Logger::WriteMessage(wlog_message()
                << "_MSC_VER = " << _MSC_VER << std::endl | as_string);
            Assert::IsTrue(1700 <= boost::lexical_cast<int>(_MSC_VER));
        }
#endif

#ifdef VEX_HAS_CPP_11_FEATURE_SET_3
        TEST_METHOD(vex_has_cpp_11_feature_set_3)
        {
            Logger::WriteMessage(wlog_message()
                << "_MSC_VER = " << _MSC_VER << std::endl | as_string);
            Assert::IsTrue(1800 <= boost::lexical_cast<int>(_MSC_VER));
        }

        class test_base {
            test_base(test_base const&) = delete;
            test_base& operator = (test_base const&) = delete;
        protected:
            test_base() 
                : m_int(0)
                , m_string()
                , m_stream(nullptr) {}
            test_base(int p_int, std::string p_string)
                : m_int(p_int)
                , m_string(std::move(p_string))
                , m_stream(nullptr) {}
            explicit test_base(std::ostream& p_stream)
                : m_int(0)
                , m_string()
                , m_stream(std::addressof(p_stream))
            {
            }

            ~test_base() = default;
        public:
            virtual void foo() = 0;

            int m_int;
            std::string m_string;
            std::ostream* m_stream;
        };

        template<class TBase>
        struct uses_variadic_constructor : public TBase {
            virtual void foo() {}

            template<class ...TArgs>
            uses_variadic_constructor(TArgs&& ...p_args)
                : TBase(std::forward<TArgs>(p_args)...) {}
        };

        TEST_METHOD(cpp_11_feature_set_3_can_use_variadic_constructors_as_default_ones)
        {
            {
                uses_variadic_constructor<test_base> t_sut;
                Assert::AreEqual(0, t_sut.m_int);
                Assert::AreEqual(std::string(), t_sut.m_string);
                Assert::IsTrue(nullptr == t_sut.m_stream);
            }

            {
                uses_variadic_constructor<test_base> t_sut(1, "23");
                Assert::AreEqual(1, t_sut.m_int);
                Assert::AreEqual(std::string("23"), t_sut.m_string);
                Assert::IsTrue(nullptr == t_sut.m_stream);
            }

            {
                uses_variadic_constructor<test_base> t_sut(std::cout);
                Assert::AreEqual(0, t_sut.m_int);
                Assert::AreEqual(std::string(), t_sut.m_string);
                Assert::IsTrue(std::addressof(std::cout) == t_sut.m_stream);
            }
        }
#endif
    };
}}